package com.chenchao.net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;

/**
 * @encoding : UTF-8
 * @Time : 2020/11/25 12:58
 * @Author : Chen Chao
 * @File : javaSE.com.chenchao.net.Test07UDP.java
 * @Software : IntelliJ IDEA
 * @since : 1.8
 * UDP聊天
 */
public class Test07  {
    private boolean exit;
    public static final String CLOSE = "close";

    private int fromPort;
    private Client client;
    private Server server;

    /**
     * 客户端创建应答器
     * @param toPort 要访问的服务端端口
     * @param toAddress 要访问的服务端主机名称
     */
    public Test07(int toPort, String toAddress){
        client=new Client(toPort,toAddress);
        server = new Server();
    }

    /**
     * 服务端创建应答器
     * @param fromPort 指定的端口
     */
    public Test07(int fromPort){
        this.fromPort = fromPort;
        server = new Server(fromPort);
    }

    /**
     * 启动应答器
     */
    public void start(){
        clientStart();
        serverStart();
    }

    /**
     * 启动client
     */
    public void clientStart(){
        if(client==null){ return; }
        initServer();
        System.out.println("client启动:本地端口"+client.socket.getLocalPort());

        new Thread(() -> {
            while (true) {
                try {
                    /*从控制台录入内容打包发送*/
                    String s = client.br.readLine();
                    client.datagramPacket.setData(s.getBytes(),0,s.getBytes().length);
                    client.socket.send(client.datagramPacket);

                    /*判断用户是否要离开*/
                    if (CLOSE.equals(s.trim()) || exit) {
                        System.out.println("您即将离开Client");
                        break;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            client.socket.close();
        }).start();

    }

    /**
     * 启动server
     */
    public void serverStart(){
        if(server==null){
            return;
        }
        System.out.println("Server启动:本地端口"+server.socket.getLocalPort());

        if(client==null){
            initClient();
        }

        new Thread(() -> {
            while (true) {
                try {
                    /*取货*/
                    server.socket.receive(server.datagramPacket);
                    /*拆包*/

                    String s = new String(server.datagramPacket.getData(),
                            0,server.datagramPacket.getLength());
                    System.out.println(server.datagramPacket.getData().length);
                    System.out.println(server.datagramPacket.getLength());

                    /*注意点：server.datagramPacket.getLength()获取的是接收到的内容的长度*/
                    /*server.datagramPacket.getData().length获取的是容器长度，
                    会把上次没有覆盖的也打印出来*/

                    /*判断对方是否离开*/
                    if (CLOSE.equals(s.trim())||exit) {
                        System.out.println("对方已离开！");
                        exit = true;
                        break;
                    }
                    /*打印输出语句*/
                    System.out.println("收到消息:"+s);

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            server.socket.close();
        }).start();

    }

    /**
     * 服务端的client初始化
     */
    public void initClient(){
        try {
            /*取包*/
            server.socket.receive(server.datagramPacket);
            System.out.println("获得对方server端口与主机名");
            /*拆包获取端口号和主机名*/
            int port = Integer.parseInt(new String(server.datagramPacket.getData()).trim());
            /*Integer.parseInt（）一定要剪除字符串的空格，不然会报错*/
            String hostName = server.datagramPacket.getAddress().getHostName();

            /*启动client*/
            System.out.println("远程port:"+port+",远程主机名"+hostName);
            client=new Client(port,hostName);
            clientStart();

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 客户端的server初始化
     */
    public void initServer(){
        if(fromPort==0){
            System.out.println("初始化server");
            fromPort = server.socket.getLocalPort();

            client.datagramPacket.setData((fromPort+"").getBytes());
            try {
                client.socket.send(client.datagramPacket);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 模拟服务端等待客户机
     * @param args args
     */
    public static void main(String[] args) {
        Test07 test07 = new Test07(9090);
        test07.start();
    }

}

class Client {
    DatagramSocket socket = null;
    DatagramPacket datagramPacket = null;
    /*以控制台作为信息来源*/
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    public Client( int toPort, String toAddress) {
        try {
            /*新建接收端口*/
            socket = new DatagramSocket();
            byte[] bytes = new byte[1024];
            /*新建包裹,包含寄件位置和端口号*/
            datagramPacket = new DatagramPacket
                    (bytes, 0, bytes.length, InetAddress.getByName(toAddress), toPort);

        } catch (SocketException | UnknownHostException e) {
            e.printStackTrace();
        }
    }

}

class Server {
    /*建码头*/
    DatagramSocket socket = null;
    /*建集装箱*/
    DatagramPacket datagramPacket = new DatagramPacket(new byte[1024], 0, 1024);

    public Server(int port) {
        try {
            socket = new DatagramSocket(port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public Server() {
        try {
            socket = new DatagramSocket();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}